/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package managedbean.Warehouse;

import entity.BatchRequired;
import entity.Credit;
import entity.Customer;
import entity.Inventory;
import entity.Invoice;
import entity.Payment;
import entity.Product;
import entity.ProductionBatch;
import entity.ProductionScheduleDay;
import entity.PurchaseItem;
import entity.Shipping;
import entity.WarehouseZone;
import entity.PurchaseOrder;
import entity.SalesOrder;
import entity.TrackingItem;
import entity.Warehouse;
import java.io.Serializable;
import java.sql.Timestamp;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import managedbean.EmailManager;
import managedbean.UserSessionManagerBean;
import org.primefaces.event.SelectEvent;
import session.stateless.CreditSessionBeanLocal;
import session.stateless.LogSessionBeanLocal;
import session.stateless.ProductionBatchSessionBeanLocal;
import session.stateless.SalesOrderSessionBeanLocal;
import session.stateless.ShippingSessionBeanLocal;
import session.stateless.WarehouseSessionBeanLocal;

/**
 *
 * @author Wx
 */
@ManagedBean(name = "shippingManagerBean")
@RequestScoped
public class ShippingManagerBean implements Serializable {

    @EJB
    ShippingSessionBeanLocal shippingSessionBeanLocal;
    @EJB
    LogSessionBeanLocal logSessionBeanLocal;
    @EJB
    ProductionBatchSessionBeanLocal productionBatchSessionBeanLocal;
    @EJB
    WarehouseSessionBeanLocal warehouseSessionBeanLocal;
    @EJB
    SalesOrderSessionBeanLocal salesOrderSessionBeanLocal;
    @EJB
    CreditSessionBeanLocal creditSessionBeanLocal;
    @ManagedProperty(value = "#{userSessionManagerBean}")
    private UserSessionManagerBean userSessionManagerBean;
    private String loadManageShippingOrders;
    private List<Shipping> shippingOrders = new ArrayList<Shipping>();
    private Shipping selectedShippingOrder;
    private String loadAddShippingOrder;
    private String loadViewShippingOrder;
    private List<ProductionBatch> productionBatches = new ArrayList<ProductionBatch>();
    private ProductionBatch selectedProductionBatch;
    private List<PurchaseItem> purchaseItems = new ArrayList<PurchaseItem>();
    private PurchaseItem selectedPurchaseItem;
    private List<Invoice> invoices;
    private Customer selectedCustomer;
    //Shipping
    private Date deliveryDate;

    /** Creates a new instance of ShippingManagerBean */
    public ShippingManagerBean() {
    }

    public void viewShippingOrder(ActionEvent event) {
        try {
            if (selectedShippingOrder != null) {
                userSessionManagerBean.setSelectedShippingOrder(selectedShippingOrder);

                FacesContext.getCurrentInstance().getExternalContext().redirect("http://"
                        + userSessionManagerBean.getServerName() + ":"
                        + userSessionManagerBean.getServerPort()
                        + "/MerlionERP-war/Web_Warehouse/viewShippingOrder.xhtml"); //redirect to viewShippingOrder.xhtml
            } else {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Please select a shipping order before continuing.", ""));
            }
        } catch (Exception ex) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.toString(), ""));
            ex.printStackTrace();
        }
    }

    public void dequeueProductionBatchFromWH() {
        List<Warehouse> temp = warehouseSessionBeanLocal.getWarehouses();

        for (Warehouse w : temp) {
            List<ProductionBatch> temp2 = w.getProductionBatches();

            for (ProductionBatch pb : temp2) {
                ProductionScheduleDay psd = pb.getProductionScheduleDay();

                Boolean isAllFulfilled = true;

                List<PurchaseItem> temp3 = new ArrayList(psd.getPurchaseItems());

                for (PurchaseItem pi : temp3) {
                    if (!pi.getIsDelivered()) { //if at least one pi is not delivered yet
                        isAllFulfilled = false;
                    }
                }

                if (isAllFulfilled) { //all pi have been delivered
                    shippingSessionBeanLocal.dequeueProductionBatchFromWH(w.getId(), pb.getId());
                }
            }
        }
    }

    public void sendInvoice(Customer customer) {
        EmailManager em = new EmailManager();

        String subject = "Invoice for Final Payment";

        String msg = "Dear " + customer.getCompany() + ",\n\n";

        Invoice invoice = creditSessionBeanLocal.getInvoice(selectedPurchaseItem.getId(), "Pending Payment", "Final Payment");

        msg += "Invoice No.: " + invoice.getId() + "\n";

        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        StringBuilder sb = new StringBuilder(sdf.format(invoice.getInvoiceDate()));

        msg += "Invoice Date: " + sb + "\n";
        msg += "Purchase Item: " + selectedPurchaseItem.getProduct().getName() + "\n";
        msg += "Purchase Quantity: " + selectedPurchaseItem.getQuantity() + "\n";

        NumberFormat nf = NumberFormat.getCurrencyInstance();

        msg += "Amount to Pay: " + nf.format(selectedPurchaseItem.getOutstandingAmount()) + "\n";
        msg += "Remarks: Please remember to make payment within 30 days after the invoice date.\n\n";
        msg += "Regards,\nMerlion Food Limited";

        String sender = "mf.merlionerp@gmail.com";
        String receiver = customer.getEmail();
        String password = "merlionfood";

        System.out.println("Sending final invoice to " + receiver + "...");

        em.sendEmail(subject, msg, sender, receiver, password);
    }

    public void addAShippingOrder(ActionEvent event) {
        try {
            if (selectedPurchaseItem != null) {
                List<BatchRequired> temp = new ArrayList<BatchRequired>();

                temp = selectedPurchaseItem.getBatchesRequired();

                for (BatchRequired br : temp) {
                    ProductionBatch pb = br.getProductionBatch();

                    pb.setUtilizedQuantity(pb.getUtilizedQuantity() + br.getQuantity());

                    //update pb
                    productionBatchSessionBeanLocal.updateProductionBatch(pb);

                    WarehouseZone wz = pb.getWarehouseZone();
                    Product p = pb.getProduct();

                    Inventory i = warehouseSessionBeanLocal.getInventoryByProduct(p.getName());

                    i.setQuantity(i.getQuantity() - br.getQuantity());

                    //update inventory
                    warehouseSessionBeanLocal.updateInventory(i);

                    i = warehouseSessionBeanLocal.getInventoryByProduct(p.getName());

                    TrackingItem ti = new TrackingItem();
                    ti.setDescription("-" + br.getQuantity());

                    warehouseSessionBeanLocal.updateInventory(i, ti);

                    Double weight = round((p.getWeight() * br.getQuantity()) / 1000, 2);

                    wz.setCurrentQuantity(wz.getCurrentQuantity() - weight);

                    //update wz
                    warehouseSessionBeanLocal.updateWarehouseZone(wz);
                }

                Timestamp ts = new Timestamp(deliveryDate.getTime());

                Shipping shippingOrder = new Shipping(ts, selectedPurchaseItem);

                shippingSessionBeanLocal.addShippingOrder(shippingOrder);
                shippingSessionBeanLocal.updatePurchaseItem(selectedPurchaseItem.getId(), true, "Pending Final Payment");

                Double outstandingAmount = selectedPurchaseItem.getOutstandingAmount();

                PurchaseOrder po = salesOrderSessionBeanLocal.getPurchaseOrderByPurchaseItem(selectedPurchaseItem.getId());

                Customer customer = po.getCustomer();
                Credit credit = customer.getCredit();

                if (po.getCreditRate() > 0) { //if required to send final invoice
                    Calendar cal = Calendar.getInstance();
                    ts = new Timestamp(cal.getTime().getTime());

                    Invoice invoice = new Invoice(ts, outstandingAmount, selectedPurchaseItem, "Pending Payment", "Final Payment");

                    creditSessionBeanLocal.updateCredit(credit.getId(), invoice);

                    logSessionBeanLocal.addLog("New invoice", "Invoice created and sent: " + userSessionManagerBean.getUserId(), "addShippingOrder.xhtml", userSessionManagerBean.getUserId());
                }

                //get 1st invoice for advance payment
                Invoice invoice = creditSessionBeanLocal.getInvoice(selectedPurchaseItem.getId(), "Paid", "Advance Payment");

                //realise deposit to actual payment
                Payment payment = creditSessionBeanLocal.getPayment(invoice.getId());
                creditSessionBeanLocal.updatePayment(payment.getId(), "Actual Payment");

                //deposit realised into actual payment
                credit.setDeposit(credit.getDeposit() - payment.getAmountPaid());
                creditSessionBeanLocal.updateCredit(credit.getId(), credit);

                SalesOrder salesOrder = salesOrderSessionBeanLocal.getSalesOrderByPO(po.getId());

                TrackingItem ti = new TrackingItem();
                ti.setDescription("Purchase item id " + selectedPurchaseItem.getId() + " of sales order id " + salesOrder.getId() + " shipped.");

                //add ti to sales order's tracking items
                salesOrderSessionBeanLocal.updateSalesOrder(salesOrder.getId(), ti);

                logSessionBeanLocal.addLog("New shipment", "Shipping order created and sent: " + userSessionManagerBean.getUserId(), "addShippingOrder.xhtml", userSessionManagerBean.getUserId());

                if (po.getCreditRate() > 0) {
                    sendInvoice(customer);
                }
                //end of finance 

                dequeueProductionBatchFromWH();

                //redirect to success page
                ArrayList<String> al = new ArrayList<String>();
                al.add("Shipping order");
                al.add("You have successfully added the shipping order.");
                al.add("Click on the link to to ");
                al.add("continue");
                al.add("Web_Warehouse/searchShippingOrders.xhtml");
                userSessionManagerBean.setSelectedItem(al);

                logSessionBeanLocal.addLog("Add shipping order", "Shipping order created: " + userSessionManagerBean.getUserId(), "addShippingOrder.xhtml", userSessionManagerBean.getUserId());

                FacesContext.getCurrentInstance().getExternalContext().redirect("http://"
                        + userSessionManagerBean.getServerName() + ":"
                        + userSessionManagerBean.getServerPort()
                        + "/MerlionERP-war/success.xhtml");
            } else {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Please selecte a purchase item before continuing.", ""));
            }
        } catch (Exception ex) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.toString(), ""));
            ex.printStackTrace();
        }
    }

    public void back(ActionEvent event) {
        try {
            if (event.getComponent().getId().equals("btnBackFromAddShippingOrder")) {
                FacesContext.getCurrentInstance().getExternalContext().redirect("http://"
                        + userSessionManagerBean.getServerName() + ":"
                        + userSessionManagerBean.getServerPort()
                        + "/MerlionERP-war/Web_Warehouse/searchShippingOrders.xhtml"); //redirect to searchShippingOrders.xhtml
            } else if (event.getComponent().getId().equals("btnBackFromViewShippingOrder")) {
                FacesContext.getCurrentInstance().getExternalContext().redirect("http://"
                        + userSessionManagerBean.getServerName() + ":"
                        + userSessionManagerBean.getServerPort()
                        + "/MerlionERP-war/Web_Warehouse/searchShippingOrders.xhtml"); //redirect to searchShippingOrders.xhtml
            }
        } catch (Exception ex) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.toString(), ""));
            ex.printStackTrace();
        }
    }

    public void onRowSelect(SelectEvent event) {
        try {
            try { //reload page on select of productionBatches
                if (event.getComponent().getId().equals("productionBatches")) {
                    purchaseItems = new ArrayList(selectedProductionBatch.getProductionScheduleDay().getPurchaseItems());

                    userSessionManagerBean.setPurchaseItems(purchaseItems);
                    userSessionManagerBean.setProductionBatches(productionBatches);

                    FacesContext.getCurrentInstance().getExternalContext().redirect("http://"
                            + userSessionManagerBean.getServerName() + ":"
                            + userSessionManagerBean.getServerPort()
                            + "/MerlionERP-war/Web_Warehouse/addShippingOrder.xhtml");
                } else if (event.getComponent().getId().equals("purchaseItems")) {
                }
            } catch (Exception ex) {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.toString(), ""));
            }
        } catch (Exception ex) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.toString(), ""));
        }
    }

    public void addShippingOrder(ActionEvent event) {
        try {
            FacesContext.getCurrentInstance().getExternalContext().redirect("http://"
                    + userSessionManagerBean.getServerName() + ":"
                    + userSessionManagerBean.getServerPort()
                    + "/MerlionERP-war/Web_Warehouse/addShippingOrder.xhtml"); //redirect to addShippingOrder.xhtml
        } catch (Exception ex) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.toString(), ""));
        }
    }

    /**
     * @return the loadManageShippingOrders
     */
    public String getLoadManageShippingOrders() {
        shippingOrders = shippingSessionBeanLocal.getShippingOrders();

        return null;
    }

    /**
     * @param loadManageShippingOrders the loadManageShippingOrders to set
     */
    public void setLoadManageShippingOrders(String loadManageShippingOrders) {
        this.loadManageShippingOrders = loadManageShippingOrders;
    }

    /**
     * @return the selectedShippingOrder
     */
    public Shipping getSelectedShippingOrder() {
        return selectedShippingOrder;
    }

    /**
     * @param selectedShippingOrder the selectedShippingOrder to set
     */
    public void setSelectedShippingOrder(Shipping selectedShippingOrder) {
        this.selectedShippingOrder = selectedShippingOrder;
    }

    /**
     * @return the userSessionManagerBean
     */
    public UserSessionManagerBean getUserSessionManagerBean() {
        return userSessionManagerBean;
    }

    /**
     * @param userSessionManagerBean the userSessionManagerBean to set
     */
    public void setUserSessionManagerBean(UserSessionManagerBean userSessionManagerBean) {
        this.userSessionManagerBean = userSessionManagerBean;
    }

    /**
     * @return the shippingOrders
     */
    public List<Shipping> getShippingOrders() {
        return shippingOrders;
    }

    /**
     * @param shippingOrders the shippingOrders to set
     */
    public void setShippingOrders(List<Shipping> shippingOrders) {
        this.shippingOrders = shippingOrders;
    }

    /**
     * @return the loadAddShippingOrder
     */
    public String getLoadAddShippingOrder() {
        purchaseItems = salesOrderSessionBeanLocal.getPurchaseItemsByStatus("Ready for Shipping");

        return null;
    }

    /**
     * @param loadAddShippingOrder the loadAddShippingOrder to set
     */
    public void setLoadAddShippingOrder(String loadAddShippingOrder) {
        this.loadAddShippingOrder = loadAddShippingOrder;
    }

    /**
     * @return the productionBatches
     */
    public List<ProductionBatch> getProductionBatches() {
        return productionBatches;
    }

    /**
     * @param productionBatches the productionBatches to set
     */
    public void setProductionBatches(List<ProductionBatch> productionBatches) {
        this.productionBatches = productionBatches;
    }

    /**
     * @return the selectedProductionBatch
     */
    public ProductionBatch getSelectedProductionBatch() {
        return selectedProductionBatch;
    }

    /**
     * @param selectedProductionBatch the selectedProductionBatch to set
     */
    public void setSelectedProductionBatch(ProductionBatch selectedProductionBatch) {
        this.selectedProductionBatch = selectedProductionBatch;
    }

    /**
     * @return the purchaseItems
     */
    public List<PurchaseItem> getPurchaseItems() {
        return purchaseItems;
    }

    /**
     * @param purchaseItems the purchaseItems to set
     */
    public void setPurchaseItems(List<PurchaseItem> purchaseItems) {
        this.purchaseItems = purchaseItems;
    }

    /**
     * @return the deliveryDate
     */
    public Date getDeliveryDate() {
        return deliveryDate;
    }

    /**
     * @param deliveryDate the deliveryDate to set
     */
    public void setDeliveryDate(Date deliveryDate) {
        this.deliveryDate = deliveryDate;
    }

    /**
     * @return the selectedPurchaseItem
     */
    public PurchaseItem getSelectedPurchaseItem() {
        return selectedPurchaseItem;
    }

    /**
     * @param selectedPurchaseItem the selectedPurchaseItem to set
     */
    public void setSelectedPurchaseItem(PurchaseItem selectedPurchaseItem) {
        this.selectedPurchaseItem = selectedPurchaseItem;
    }

    public double round(double valueToRound, int numberOfDecimalPlaces) {
        double multiplicationFactor = Math.pow(10, numberOfDecimalPlaces);
        double interestedInZeroDPs = valueToRound * multiplicationFactor;

        return Math.round(interestedInZeroDPs) / multiplicationFactor;
    }

    /**
     * @return the loadViewShippingOrder
     */
    public String getLoadViewShippingOrder() {
        selectedShippingOrder = userSessionManagerBean.getSelectedShippingOrder();

        deliveryDate = selectedShippingOrder.getDeliveryDate();

        invoices = creditSessionBeanLocal.getInvoices(selectedShippingOrder.getPurchaseItem().getId());

        PurchaseOrder po = salesOrderSessionBeanLocal.getPurchaseOrderByPurchaseItem(selectedShippingOrder.getPurchaseItem().getId());

        selectedCustomer = po.getCustomer();

        return null;
    }

    /**
     * @param loadViewShippingOrder the loadViewShippingOrder to set
     */
    public void setLoadViewShippingOrder(String loadViewShippingOrder) {
        this.loadViewShippingOrder = loadViewShippingOrder;
    }

    /**
     * @return the invoices
     */
    public List<Invoice> getInvoices() {
        return invoices;
    }

    /**
     * @param invoices the invoices to set
     */
    public void setInvoices(List<Invoice> invoices) {
        this.invoices = invoices;
    }

    /**
     * @return the selectedCustomer
     */
    public Customer getSelectedCustomer() {
        return selectedCustomer;
    }

    /**
     * @param selectedCustomer the selectedCustomer to set
     */
    public void setSelectedCustomer(Customer selectedCustomer) {
        this.selectedCustomer = selectedCustomer;
    }
}
